package mx.com.crowdgine.display.animation.skinning;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import mx.com.crowdgine.assetloader.BitmapLoader;
import mx.com.crowdgine.assetloader.Face;
import mx.com.crowdgine.assetloader.ObjLoader;
import mx.com.crowdgine.assetloader.TexCoordinate;
import mx.com.crowdgine.assetloader.Vertex;

public class ImageBasedSkinningEncoder {
	
	private ObjLoader objLoader = new ObjLoader();
	private BufferedImage jointImage;
	private Map<Integer, Set<Vertex>> jointMap = new HashMap<Integer, Set<Vertex>>();
	private List<Vertex> jointList = new ArrayList<Vertex>();
	private SortedSet<Integer> jointIds;
	
	public ImageBasedSkinningEncoder(String objFilePath, String jointImageFilePath) {
		
		
		BufferedReader br;
		try {
			
			br = new BufferedReader(new FileReader(objFilePath));
			objLoader.readModel(br);
			
			jointImage = BitmapLoader.loadBitmap(jointImageFilePath);
			
			encode();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	private void encode() {
		
		createJointMap();
		extractCentroids();
		
	}

	public void extractCentroids() {
		jointIds = new TreeSet<Integer>();
		jointIds.addAll(jointMap.keySet());
		Set<Vertex> vertices = null;
		Vertex centroid = null;
		
		for(Integer id : jointIds) {
			
			vertices = jointMap.get(id);
			centroid = new Vertex(0f, 0f, 0f);
			
			for(Vertex vertex : vertices) {
				centroid.getVertexData().plus(vertex.getVertexData());
			}
			
			centroid.getVertexData().scale(1.0f/((float)vertices.size()));	
			this.jointList.add(centroid);
		}
	}

	public void createJointMap() {
		Integer jointId;
		for(Face face : objLoader.getFaces()) {
			for(int i = 0; i < face.getNumVertices(); i++) {
				jointId = getJointId(face.getTexCoordinate(i));
				
				if(jointId != -1) {
					if(jointMap.get(jointId) == null) {
						jointMap.put(jointId, new HashSet<Vertex>());
					}
					
					if(!jointMap.get(jointId).contains(face.getVertex(i))) {
						jointMap.get(jointId).add(face.getVertex(i));
					}
				}
				
			}
		}
	}
	
	
	private Integer getJointId(TexCoordinate coord) {
		
		int x = (int)(coord.getTexCoordData().getX() * jointImage.getWidth());
		int y = (int)(coord.getTexCoordData().getY() * jointImage.getHeight());
		
		int rgb = jointImage.getRGB(x, y);
		
		Integer jointId = (int)(byte)(rgb >> 16); // joint id is in r component
		
		return jointId;
		
	}
	
	
	public List<Vertex> getJointList() {
		return this.jointList;
	}
	
	public List<Integer> getJointIds() {
		List<Integer> jointIdList = new ArrayList<Integer>();
		jointIdList.addAll(this.jointIds);
		return jointIdList;
	}
	
	
	public float [] getJointData() {
		
		float [] jointData = new float[this.jointList.size() * 3];
		
		for(int i = 0; i < this.jointList.size(); i++) {
			jointData[i*3 + 0] = jointList.get(i).getVertexData().getX();
			jointData[i*3 + 1] = jointList.get(i).getVertexData().getY();
			jointData[i*3 + 2] = jointList.get(i).getVertexData().getZ();
		}
		
		return jointData;
	}
	
	
	
}
